<template>
  <view
    class="mxp-count-down-button"
    :style="[newStyle, cusStyle]"
    :class="newClass"
    hoverClass="hover-class"
    :hoverStartTime="0"
    :hoverStayTime="0"
    @click="onClick"
  >
    <slot>
      <mxp-icon v-if="data.loading" name="jiazai" :spin="true" :color="iconColor || (newStyle['--hover-color'] as $AllColorStr)" :size="iconSize"></mxp-icon>
      <text class="text" :style="{ fontSize, lineHeight: fontSize }">{{ data.loading ? loadingText : data.text }}</text>
    </slot>
  </view>
</template>

<script lang="ts" setup>
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import { type CSSProperties, type PropType, computed, onMounted, onUnmounted, shallowReactive, watch } from 'vue';
  import type { $AllColorStr, $ColorType, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import mxpIcon from '@/mxp-ui/mxp-icon/mxp-icon.vue';
  import { defThemeColor } from '../mxp-tool/theme/theme';
  import { isDarkColorStorage, lightenDarkenColorStorage } from '../mxp-tool/utils/color';
  defineOptions({
    name: 'mxp-count-down-button',
  });

  const props = defineProps({
    /** 倒计时总秒数 */
    seconds: { type: Number, default: 60 },
    /** 尚未开始时提示 */
    startText: { type: String, default: '获取验证码' },
    /** 倒计时前缀 */
    prefix: { type: String, default: '' },
    /** 倒计时后缀 */
    suffix: { type: String, default: '秒后可获取' },
    /** 倒计时结束时的提示 */
    endText: { type: String, default: '重新获取' },
    /** 当在发送网络请求时的文字（loading为 true 时） */
    loadingText: { type: String, default: '正在获取' },
    /** 是否缓存倒计时 （从新进来时继续倒计时） */
    cache: { type: Boolean, default: true },
    /** 当有缓存时需要用onlyKey来存储时间，主要用于本地存储的key */
    storageKey: { type: String, default: '' },
    /** 字体颜色 */
    color: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 是否为文字按钮 */
    isTextButton: { type: Boolean, default: true },
    /** 按钮是否镂空 */
    plain: { type: Boolean, default: false },
    /** 镂空时是否有背景色 */
    plainBackground: { type: Boolean, default: true },
    /** 镂空时是否有边框 */
    plainBorder: { type: Boolean, default: false },
    /** 字体大小 */
    fontSize: { type: String as PropType<$SizeUnitStr>, default: '12px' },
    /** 按钮的预置样式支持 "error" | "info" | "primary" | "success" | "warning" 和自定义的颜色（支持渐变色） 如#ff0000 */
    background: { type: String as PropType<$AllColorStr | $ColorType>, default: 'primary' },
    /** 加载图标颜色 */
    iconColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 加载图标大小 */
    iconSize: { type: String as PropType<$SizeUnitStr>, default: '12px' },
    /** 是否禁用 */
    disabled: { type: Boolean, default: false },
    ...publicStyeProps,
  });
  defineSlots<{
    /** 主体内容 */
    default?: () => void;
  }>();
  const emits = defineEmits<{
    (e: 'click'): void;
    (e: 'start'): void;
    (e: 'countDownChange', text: number): void;
    (e: 'change', state: 0 | 1 | 2): void;
    (e: 'end'): void;
  }>();

  const data = shallowReactive({
    /** 是否正在发送网络请求 */
    loading: false,
    /** 剩余时间 */
    countDown: props.seconds,
    /** Timeout */
    timer: null as NodeJS.Timeout | null,
    /** 倒计时状态 0未倒计时，1正在倒计时，2倒计时完成 */
    status: 0 as 0 | 1 | 2,
    /** 显示的文本 */
    text: props.startText,
  });

  const newStorageKey = computed(() => `mxp-count-down-button_${String(props.storageKey)}`);
  const newClass = computed(() => {
    const cla: string[] = [props.cusClass, props.isTextButton ? 'text' : props.plain ? 'plain' : 'bg'];
    (data.status === 1 || props.disabled || data.loading) && cla.push('hover-class');
    return cla;
  });
  const newStyle = computed<CSSProperties>(() => {
    const obj: CSSProperties = {};

    if (props.isTextButton) {
      obj.border = 'none';
      obj.borderRadius = '0px';
      obj.display = 'inline-flex';
      obj.width = 'auto';
    }
    /** 背景 */
    const bg = props.background in defThemeColor.value ? defThemeColor.value[props.background as $ColorType] : props.background || defThemeColor.value.primary;

    /** 点击时的背景 */
    const hbg = lightenDarkenColorStorage(bg as string, 0.9) || bg;
    if (props.isTextButton) {
      obj['--text-background'] = 'rgba(0,0,0,0)';
      obj['--text-border-color'] = 'rgba(0,0,0,0)';
      obj['--hover-background'] = 'rgba(0,0,0,0)';
      obj['--hover-border-color'] = 'rgba(0,0,0,0)';
      obj['--text-color'] = props.color ? props.color : bg;
      obj['--hover-color'] = lightenDarkenColorStorage(props.color ? props.color : bg, 0.95) || props.color || bg;
    } else if (props.plain) {
      obj['--plain-background'] = props.plainBackground ? lightenDarkenColorStorage(bg as string, 0.1) || 'rgba(0,0,0,0)' : 'rgba(0,0,0,0)';
      obj['--plain-border-color'] = props.plainBorder ? bg : obj['--plain-background'];
      obj['--hover-background'] = props.plainBackground
        ? lightenDarkenColorStorage(obj['--plain-background'] as string, 0.9, 'light') || obj['--plain-background']
        : 'rgba(0,0,0,0)';
      obj['--hover-border-color'] = props.plainBorder ? lightenDarkenColorStorage(hbg || '', 0.8) || bg : obj['--hover-background'];
      obj['--plain-color'] = props.color ? props.color : bg;
      obj['--hover-color'] = lightenDarkenColorStorage(props.color ? props.color : hbg, 0.95) || props.color || hbg;
    } else {
      obj['--border-background'] = bg;
      obj['--background'] = bg;
      obj['--hover-background'] = hbg;
      obj['--hover-border-color'] = hbg;
      obj['--color'] = props.color
        ? props.color
        : props.background in defThemeColor.value
          ? defThemeColor.value.textLight
          : isDarkColorStorage(props.background)
            ? defThemeColor.value.text
            : defThemeColor.value.textLight;
      obj['--hover-color'] = props.color ? props.color : lightenDarkenColorStorage(obj['--color'] as string, 0.95) || obj['--color'];
    }
    return obj;
  });

  watch(
    () => props.seconds,
    (val) => {
      data.countDown = val;
    },
    { immediate: true }
  );

  watch(
    () => data.status,
    (val) => {
      emits('change', val);
    },
    { immediate: true }
  );

  onMounted(() => {
    checkcache();
  });

  onUnmounted(() => {
    setTimeToStorage();
    data.timer && clearTimeout(data.timer);
    data.timer = null;
  });

  /** 检查 */
  function checkcache() {
    const lastTimestamp = Number(uni.getStorageSync(newStorageKey.value));
    const nowTimestamp = Math.floor(Number(new Date()) / 1000);
    if (props.cache && !isNaN(lastTimestamp) && lastTimestamp && lastTimestamp > nowTimestamp) {
      data.countDown = lastTimestamp - nowTimestamp;
      uni.removeStorageSync(newStorageKey.value);
      start();
    }
  }

  /** 开始倒计时 */
  function start() {
    clearIntervalFun();
    emits('start');
    data.status = 1;
    emits('countDownChange', data.countDown);
    data.text = props.prefix + data.countDown + props.suffix;
    data.timer = setInterval(() => {
      if (--data.countDown) {
        emits('countDownChange', data.countDown);
        data.text = props.prefix + data.countDown + props.suffix;
      } else {
        clearIntervalFun();
        uni.removeStorageSync(newStorageKey.value);
        data.countDown = props.seconds;
        data.text = props.endText;
        emits('end');
        data.status = 2;
      }
    }, 1000);
    setTimeToStorage();
  }

  /** 重置，可以让用户再次获取验证码 */
  function reset() {
    data.loading = false;
    data.text = props.startText;
    clearIntervalFun();
    data.status = 0;
    data.countDown = props.seconds;
  }

  /** 保存时间戳，为了防止倒计时尚未结束，H5刷新或者各端的右上角返回上一页再进来 */
  function setTimeToStorage() {
    if (!props.cache || !data.timer) {
      return;
    }
    // 记录当前的时间戳，为了下次进入页面，如果还在倒计时内的话，继续倒计时
    // 倒计时尚未结束，结果大于0；倒计时已经开始，就会小于初始值，如果等于初始值，说明没有开始倒计时，无需处理
    if (data.countDown > 0 && data.countDown <= props.seconds) {
      // 获取当前时间戳(+ new Date()为特殊写法)，除以1000变成秒，再去除小数部分
      const nowTimestamp = Math.floor(Number(new Date()) / 1000);
      // 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数
      uni.setStorageSync(newStorageKey.value, nowTimestamp + Number(data.countDown));
    }
  }

  /** 清除计时器 */
  function clearIntervalFun() {
    if (data.timer) {
      clearInterval(data.timer);
      data.timer = null;
    }
  }

  /** 点击 */
  function onClick() {
    if (!props.disabled && data.status !== 1 && !data.loading) {
      emits('click');
    }
  }

  defineExpose({
    /** 开始倒计时 */
    start,
    /** 重置倒计时 */
    reset,
    /** 设置状态 */
    setLoadState(state: boolean) {
      data.loading = state;
    },
  });
</script>

<style lang="scss" scoped>
  .mxp-count-down-button {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    width: 90px;
    height: 30px;
    border-radius: 4px;
  }

  .text {
    background: var(--text-background);
    border: 1px solid var(--text-border);

    .text {
      color: var(--text-color);
    }
  }

  .bg {
    background: var(--background);
    border: 1px solid var(--border-background);

    .text {
      color: var(--color);
    }
  }

  .plain {
    background: var(--plain-background);
    border: 1px solid var(--plain-border-color);

    .text {
      color: var(--plain-color);
    }
  }

  .hover-class {
    background: var(--hover-background) !important;
    border: 1px solid var(--hover-border-color);

    .text {
      color: var(--hover-color);
    }
  }
</style>
